#ifndef _MY_DATA_
#define _MY_DATA_

#include "util.hpp"
#include <unistd.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#include <mutex>

// id name info video image
// 定义插入语句宏，方便字符串操作
#define INSERT_VIDEO "insert tb_video values(null,'%s','%s','%s','%s');"
// 定义更新语句宏，方便字符串操作
#define UPDATE_VIDEO "update tb_video set name='%s',info='%s' where id=%d;"
// 定义删除语句宏，方便字符串操作
#define DELETE_VIDEO "delete from tb_video where id=%d;"
// 定义查找(all)语句宏，方便字符串操作
#define SELECTALL_VIDEO "select * from tb_video;"
// 定义查找(one)语句宏，方便字符串操作
#define SELECTONE_VIDEO "select * from tb_video where id=%d;"
// 定义查找(like)语句宏，方便字符串操作
#define SELECTLIKE_VIDEO "select * from tb_video where name like '%%%s%%';" // 通配符 %%%s%%-->% %s %

namespace data
{
    // 用来连接的数据库信息类
    class Database
    {
    public:
        Database( // const char *host,
            const char *user,
            const char *passwd,
            // const char *db,
            const unsigned int port)
            : // Host(host),
              User(user),
              Passwd(passwd),
              // Db(db),
              Port(port)
        {
        }
        const char *GetHost()
        {
            return Host;
        }
        const char *GetUser()
        {
            return User;
        }
        const char *GetPasswd()
        {
            return Passwd;
        }
        const char *GetDb()
        {
            return Db;
        }
        unsigned int GetPort()
        {
            return Port;
        }
        ~Database()
        {
        }

    private:
        const char *Host = "127.0.0.1";
        const char *User = "root";
        const char *Passwd;
        const char *Db = "vod_system";
        unsigned int Port;
    };

    // 初始化句柄
    static MYSQL *MysqlInit()
    {
        // 初始化句柄
        MYSQL *mysql = mysql_init(nullptr);
        if (mysql == NULL)
        {
            std::cout << "init mysql instance failed!" << std::endl;
            return NULL;
        }
        // 实例化数据库信息类
        Database ds("root", "密码", 8080);
        // 连接mysql数据库
        if (mysql_real_connect(mysql, ds.GetHost(), ds.GetUser(),
                               ds.GetPasswd(), ds.GetDb(), ds.GetPort(), NULL, 0) == NULL)
        {
            std::cout << "连接mysql失败!" << std::endl;
            printf("%s\n", mysql_error(mysql));

            // 重要！！避免资源泄露
            mysql_close(mysql);
            return NULL;
        }
        // 设置客户端字符集
        mysql_set_character_set(mysql, "utf8");
        return mysql;
    }

    // 销毁句柄
    static void MysqlDestory(MYSQL *mysql)
    {
        if (mysql != NULL)
            mysql_close(mysql);
        return;
    }

    // 执行语句
    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)
    {
        if (mysql_query(mysql, sql.c_str()) != 0)
        {
            std::cout << sql << " error!\n"
                      << mysql_error(mysql) << std::endl;
            return false;
        }
        return true;
    }

    // 视频信息表
    class TableVideo
    {
    public:
        TableVideo()
        {
            // 构造时初始化句柄
            _mysql = MysqlInit();
            if (_mysql == NULL)
                exit(1);
        }
        bool Insert(const Json::Value &video) // 插入视频信息
        {
            // 还应该有对sql语句的校验，后面补充！！！！！
            //  id name info video image
            std::string sql;
            sql.resize(4096 + video["info"].asString().size()); // 避免简介过长
            // // 定义插入语句宏，方便字符串操作
            // #define INSERT_VIDEO "insert tb_video values(null,'%s','%s','%s','%s')"
            sprintf(&sql[0], INSERT_VIDEO, video["name"].asCString(),
                    video["info"].asCString(),
                    video["video"].asCString(),
                    video["image"].asCString());
            return MysqlQuery(_mysql, sql);
        }
        bool Update(int video_id, Json::Value &video) // 更新视频信息
        {
            std::string sql;
            sql.resize(4096 + video["info"].asString().size()); // 避免简介过长

            sprintf(&sql[0], UPDATE_VIDEO, video["name"].asCString(),
                    video["info"].asCString(),
                    video_id);
            return MysqlQuery(_mysql, sql);
        }
        bool Delete(int video_id) // 删除视频信息
        {
            std::string sql;
            sql.resize(1024);
            sprintf(&sql[0], DELETE_VIDEO, video_id);
            return MysqlQuery(_mysql, sql);
        }
        bool SelectAll(Json::Value *videos) // 查找全部视频
        {
            // std::string sql(SELECTALL_VIDEO);
            _mutex.lock(); // 加锁，保护查询与保存结果到本地的过程
            if (MysqlQuery(_mysql, SELECTALL_VIDEO) == false)
            {
                _mutex.unlock();
                return false;
            }
            // 查询成功，保存结果集并打印
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "mysql store result failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock(); // 解锁
            int num_rows = mysql_num_rows(res);
            // int num_cols=mysql_num_fields(res);//这里设计默认5行，就不调用接口了
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]);
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }
            mysql_free_result(res);
            return true;
        }
        bool SelectOne(int video_id, Json::Value *videos) // 查找某一个视频
        {
            std::string sql;
            sql.resize(1024);
            sprintf(&sql[0], SELECTONE_VIDEO, video_id);
            _mutex.lock(); // 加锁，保护查询与保存结果到本地的过程
            if (MysqlQuery(_mysql, sql) == false)
            // bool ret = MysqlQuery(_mysql, sql);
            // if (ret)
            {
                _mutex.unlock();
                return false;
            }
            // 查询成功，保存结果集并打印
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "mysql store result failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock(); // 解锁
            int num_rows = mysql_num_rows(res);
            if (num_rows != 1)
            {
                std::cout << "have no data!" << std::endl;
                mysql_free_result(res);
                return false;
            }
            MYSQL_ROW row = mysql_fetch_row(res);
            (*videos)["id"] = atoi(row[0]);
            (*videos)["name"] = row[1];
            (*videos)["info"] = row[2];
            (*videos)["video"] = row[3];
            (*videos)["image"] = row[4];
            // videos->append(video);

            mysql_free_result(res);
            return true;
        }
        bool SelectLike(const std::string &key, Json::Value *videos) // 模糊查找
        {
            std::string sql;
            sql.resize(1024);
            sprintf(&sql[0], SELECTLIKE_VIDEO, key.c_str());
            _mutex.lock(); // 加锁，保护查询与保存结果到本地的过程
            if (MysqlQuery(_mysql, sql) == false)
            {
                _mutex.unlock();
                return false;
            }
            // 查询成功，保存结果集并打印
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "mysql store result failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock(); // 解锁
            int num_rows = mysql_num_rows(res);
            // int num_cols = mysql_num_fields(res); // 这里设计默认5行，就不调用接口了
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]);
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }
            mysql_free_result(res);
            return true;
        }

        ~TableVideo()
        {
            // 析构时销毁句柄
            MysqlDestory(_mysql);
        }

    private:
        MYSQL *_mysql;     // ⼀个对象就是⼀个客户端，管理⼀张表
        std::mutex _mutex; // 防备操作对象在多线程中使⽤存在的线程安全问题
    };
}

#endif
